1   package org.csstudio.swt.xygraph.linearscale;
2   
3   import java.util.ArrayList;
4   
5   import org.csstudio.swt.xygraph.linearscale.AbstractScale.LabelSide;
6   import org.csstudio.swt.xygraph.util.SWTConstants;
7   import org.eclipse.draw2d.Figure;
8   import org.eclipse.draw2d.Graphics;
9   
10  /**
11   * Linear scale tick marks.
12   * @author Xihui Chen
13   */
14  public class LinearScaleTickMarks extends Figure {   
15  
16  
17  
18  	/** the scale */
19      private LinearScale scale;
20  
21      /** the line width */
22      protected static final int LINE_WIDTH = 1;
23  
24      /** the tick length */
25      public static final int MAJOR_TICK_LENGTH = 6;
26      /** the tick length */
27      public static final int MINOR_TICK_LENGTH = 3;
28  
29      private int minorGridStepInPixel;
30      
31      private int minorTicksNumber;
32      
33      /**
34       * Constructor.
35       * @param scale
36       *            the scale
37       */
38      public LinearScaleTickMarks(LinearScale scale) {
39          
40          this.scale = scale;
41  
42          setForegroundColor(scale.getForegroundColor());
43      }
44  
45  
46      /**
47       * Gets the associated scale.
48       * 
49       * @return the scale
50       */
51      public LinearScale getAxis() {
52          return scale;
53      }
54  
55  
56     protected void paintClientArea(Graphics graphics) {
57  	   graphics.translate(bounds.x, bounds.y);
58  	   ArrayList<Integer> tickLabelPositions = scale
59                  .getScaleTickLabels().getTickLabelPositions();
60  
61          int width = getSize().width;
62          int height = getSize().height;
63  
64          if (scale.isHorizontal()) {
65              drawXTickMarks(graphics, tickLabelPositions, scale.getTickLablesSide(), width,
66                      height);
67          } else {
68              drawYTickMarks(graphics, tickLabelPositions, scale.getTickLablesSide(), width,
69                      height);
70          }
71     };
72      
73     
74  	/**
75  	 * update the parameters for minor ticks
76  	 */
77  	public void updateMinorTickParas() {
78  		if(scale.isDateEnabled()) {
79  			minorTicksNumber = 6;
80  			minorGridStepInPixel = (int) (scale.getScaleTickLabels().getGridStepInPixel()/6.0);
81  			return;
82  		}
83  			
84  		if(scale.getScaleTickLabels().getGridStepInPixel()/5 >= scale.getMinorTickMarkStepHint()){
85  			minorTicksNumber = 5;
86  			minorGridStepInPixel = (int) (scale.getScaleTickLabels().getGridStepInPixel()/5.0);
87  			return;
88  		}			
89  		if(scale.getScaleTickLabels().getGridStepInPixel()/4 >= scale.getMinorTickMarkStepHint()){
90  			minorTicksNumber = 4;
91  			minorGridStepInPixel = (int) (scale.getScaleTickLabels().getGridStepInPixel()/4.0);
92  			return;
93  		}
94  		
95  		minorTicksNumber = 2;
96  		minorGridStepInPixel = (int) (scale.getScaleTickLabels().getGridStepInPixel()/2.0);
97  		return;
98  	}
99  
100     /**
101      * Draw the X tick marks.
102      * 
103      * @param tickLabelPositions
104      *            the tick label positions
105      * @param tickLabelSide
106      *            the side of tick label relative to tick marks
107      * @param width
108      *            the width to draw tick marks
109      * @param height
110      *            the height to draw tick marks
111      * @param gc
112      *            the graphics context
113      */
114     private void drawXTickMarks(Graphics gc, ArrayList<Integer> tickLabelPositions,
115             LabelSide tickLabelSide, int width, int height) {
116     	
117     	updateMinorTickParas();
118         // draw tick marks
119         gc.setLineStyle(SWTConstants.LINE_SOLID);
120         
121         if(scale.isLogScaleEnabled()) {
122         	ArrayList<Boolean> tickLabelVisibilities = 
123         		scale.getScaleTickLabels().getTickVisibilities();        	
124         	for (int i = 0; i < tickLabelPositions.size(); i++) {
125                 int x = tickLabelPositions.get(i);
126                 int y = 0;
127                 int tickLength =0;
128                 if(tickLabelVisibilities.get(i))
129                 	tickLength = MAJOR_TICK_LENGTH;
130                 else
131                 	tickLength = MINOR_TICK_LENGTH;
132 
133                 if (tickLabelSide == LabelSide.Secondary) {
134                     y = height - 1 - LINE_WIDTH - tickLength;
135                 }
136                 //draw minor ticks for log scale
137                 if(tickLabelVisibilities.get(i) || scale.isMinorTicksVisible())
138                 	gc.drawLine(x, y, x, y + tickLength);
139         	}
140         } else {
141         	for (int i = 0; i < tickLabelPositions.size(); i++) {
142                 int x = tickLabelPositions.get(i);
143                 int y = 0;
144                 if (tickLabelSide == LabelSide.Secondary) {
145                     y = height - 1 - LINE_WIDTH - MAJOR_TICK_LENGTH;
146                 }
147                 gc.drawLine(x, y, x, y + MAJOR_TICK_LENGTH);
148                 //draw minor ticks for linear scale
149                 if(scale.isMinorTicksVisible()){
150                 	if(i>0) {
151                 		//draw the first grid step which is start from min value
152                 		if(i == 1 && (tickLabelPositions.get(1) - tickLabelPositions.get(0))
153                 				< scale.getScaleTickLabels().getGridStepInPixel()){
154                 			x = tickLabelPositions.get(1);
155                 			while((x - tickLabelPositions.get(0)) > minorGridStepInPixel + 3) {
156                 				x = x - minorGridStepInPixel;
157                 				drawXMinorTicks(gc, tickLabelSide, x, y); 
158                 			}
159                 		} //draw the last grid step which is end to max value
160                 		else if(i == tickLabelPositions.size()-1 && (tickLabelPositions.get(i) - tickLabelPositions.get(i-1))
161                 				< scale.getScaleTickLabels().getGridStepInPixel()){
162                 			x = tickLabelPositions.get(i-1);                			
163                 			while((tickLabelPositions.get(i) -x ) > minorGridStepInPixel + 3) {
164                 				x = x + minorGridStepInPixel;
165                 				drawXMinorTicks(gc, tickLabelSide, x, y); 
166                 			}
167                 		}else{ // draw regular steps
168                 			for(int j =0; j<minorTicksNumber; j++) {
169                 				x =tickLabelPositions.get(i-1) + 
170                 				(tickLabelPositions.get(i) - tickLabelPositions.get(i-1))*j/minorTicksNumber;
171                 				drawXMinorTicks(gc, tickLabelSide, x, y);
172                 			}  
173                 		}
174                 		              		
175                 	}
176                 }
177                 
178             }
179         }
180        
181             
182         
183 
184         //draw scale line
185         if(scale.isScaleLineVisible()) {
186         	if (tickLabelSide == LabelSide.Primary) {
187             gc.drawLine(scale.getMargin(), 0, width - scale.getMargin(), 0);
188         } else {
189             gc.drawLine(scale.getMargin(), height - 1, width - scale.getMargin(), height - 1);
190         }
191         }
192         
193     }
194 
195 
196 	private void drawXMinorTicks(Graphics gc, LabelSide tickLabelSide, int x,
197 			int y) {
198 		if(tickLabelSide == LabelSide.Primary)
199 			gc.drawLine(x, y, x, y + MINOR_TICK_LENGTH);
200 		else
201 			gc.drawLine(x, y + MAJOR_TICK_LENGTH - MINOR_TICK_LENGTH, 
202 					x, y + MAJOR_TICK_LENGTH);
203 	}
204 
205     /**
206      * Draw the Y tick marks.
207      * 
208      * @param tickLabelPositions
209      *            the tick label positions
210      * @param tickLabelSide
211      *            the side of tick label relative to tick marks
212      * @param width
213      *            the width to draw tick marks
214      * @param height
215      *            the height to draw tick marks
216      * @param gc
217      *            the graphics context
218      */
219     private void drawYTickMarks(Graphics gc, ArrayList<Integer> tickLabelPositions,
220             LabelSide tickLabelSide, int width, int height) {
221     	updateMinorTickParas();
222         // draw tick marks
223         gc.setLineStyle(SWTConstants.LINE_SOLID);
224         int x = 0;
225         int y = 0;
226         if(scale.isLogScaleEnabled()) {
227         	ArrayList<Boolean> tickLabelVisibilities = 
228         		scale.getScaleTickLabels().getTickVisibilities();        	
229         	for (int i = 0; i < tickLabelPositions.size(); i++) {
230         		
231                 int tickLength =0;
232                 if(tickLabelVisibilities.get(i))
233                 	tickLength = MAJOR_TICK_LENGTH;
234                 else
235                  	tickLength = MINOR_TICK_LENGTH;            
236                 
237                 if (tickLabelSide == LabelSide.Primary) {
238                     x = width - 1 - LINE_WIDTH - tickLength;
239                 } else {
240                     x = LINE_WIDTH;
241                 }
242                 y = height - tickLabelPositions.get(i);
243                 if(tickLabelVisibilities.get(i) || scale.isMinorTicksVisible())
244                 	gc.drawLine(x, y, x + tickLength, y);
245         	}
246         } else {        
247             for (int i = 0; i < tickLabelPositions.size(); i++) {
248                 if (tickLabelSide == LabelSide.Primary) {
249                     x = width - 1 - LINE_WIDTH - MAJOR_TICK_LENGTH;
250                 } else {
251                     x = LINE_WIDTH;
252                 }
253                 y = height - tickLabelPositions.get(i);
254                 gc.drawLine(x, y, x + MAJOR_TICK_LENGTH, y);
255                 //draw minor ticks for linear scale
256                 if(scale.isMinorTicksVisible()){
257                 	if(i>0) {
258                 		//draw the first grid step which is start from min value
259                 		if(i == 1 && (tickLabelPositions.get(1) - tickLabelPositions.get(0))
260                 				< scale.getScaleTickLabels().getGridStepInPixel()){
261                 			y = tickLabelPositions.get(1);
262                 			while((y - tickLabelPositions.get(0)) > minorGridStepInPixel + 3) {
263                 				y = y - minorGridStepInPixel;
264                 				drawYMinorTicks(gc, tickLabelSide, x, height - y); 
265                 			}
266                 		} //draw the last grid step which is end to max value
267                 		else if(i == tickLabelPositions.size()-1 && (tickLabelPositions.get(i) - tickLabelPositions.get(i-1))
268                 				< scale.getScaleTickLabels().getGridStepInPixel()){
269                 			y = tickLabelPositions.get(i-1);                			
270                 			while((tickLabelPositions.get(i) -y ) > minorGridStepInPixel + 3) {
271                 				y = y + minorGridStepInPixel;
272                 				drawYMinorTicks(gc, tickLabelSide, x, height - y); 
273                 			}
274                 		}else{ // draw regular steps                		
275 	                		for(int j =0; j<minorTicksNumber; j++) {
276 	                			y =height - tickLabelPositions.get(i-1) -
277 	                				(tickLabelPositions.get(i) - tickLabelPositions.get(i-1))*j/minorTicksNumber;
278 	                			drawYMinorTicks(gc, tickLabelSide, x, y);
279 	                		}  
280                 		}
281                 	}
282                 }
283             }
284         }
285 
286         // draw scale line
287         if(scale.isScaleLineVisible()) {
288         	if (tickLabelSide == LabelSide.Primary) {
289             gc.drawLine(width - 1, scale.getMargin(), width - 1, height - scale.getMargin());
290         } else {
291             gc.drawLine(0, scale.getMargin(), 0, height - scale.getMargin());
292         }
293         }
294         
295     }
296 
297 
298 	private void drawYMinorTicks(Graphics gc, LabelSide tickLabelSide, int x,
299 			int y) {
300 		//there is a misillumiation 
301 		int verticalMinorTickLength = MINOR_TICK_LENGTH -1;
302 		if(tickLabelSide == LabelSide.Primary)               				
303 			gc.drawLine(x + MAJOR_TICK_LENGTH - verticalMinorTickLength, y,
304 				x + MAJOR_TICK_LENGTH, y);
305 		else
306 			gc.drawLine(x, y,
307 				x + verticalMinorTickLength, y);
308 	}
309     
310 
311 }